import socket
import threading
import time

from flask import Flask
from flask import request, jsonify

from config.config import httpPort, tcpPort, maxTcpConn, routerPrefix
from server.tool import commonTools

# 全局客户端连接列表
clientsMap = {}


# 获取实际得数据
def getData(prefix, data):
    # 验证是否以指定字节开头
    if data.startswith(prefix):
        # 使用切片操作去除头部指定字节
        new_data = data[len(prefix):]
    return new_data


# 客户端连接处理
def connHandle(client_socket, client_address):
    identificationCode = ""
    print(f"接收来自 {client_socket} 的连接")
    try:
        while True:
            data = client_socket.recv(1024)
            # 要验证的开头字节(注册包)
            prefix = b'\x01'
            # 验证是否以指定字节开头
            if data.startswith(prefix):
                # 使用切片操作去除头部指定字节
                new_data = data[len(prefix):]
                identificationCode = int.from_bytes(new_data, 'big')
                print("客户端识别码:", identificationCode)
                # 判断是否识别码已存在 todo
                clientsMap[identificationCode] = client_socket

    except Exception as e:
        print(f"发生连接异常：{str(e)}")
    finally:
        print("移除客户端：", identificationCode)
        del clientsMap[identificationCode]


def tcpServer():
    # 服务器主机和端口
    host = '0.0.0.0'  # 监听所有可用的网络接口
    port = tcpPort  # 端口号，可以根据需要更改

    # 创建一个TCP socket
    server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)

    # 绑定主机和端口
    server_socket.bind((host, port))

    # 启动服务器，设置最大连接数
    server_socket.listen(maxTcpConn)
    print(f"服务器正在监听 {host}:{port}")

    while True:
        # 等待客户端连接
        print("等待客户端连接")
        client_socket, client_address = server_socket.accept()
        # 创建一个线程类的对象，target告诉程序当前线程执行谁，安排好任务
        t = threading.Thread(target=connHandle, args=(client_socket, client_address))
        # 多线程状态为可以开始执行了，具体执行时间由CPU决定
        t.start()


app = Flask(__name__)
# 允许上传的文件类型（可根据需求自行扩展）
ALLOWED_EXTENSIONS = {'txt', 'pdf', 'png', 'jpg', 'jpeg', 'gif', 'xls', 'xlsx', 'doc', 'ppt', 'docx'}


# 检查文件扩展名是否允许
def allowed_file(filename):
    return '.' in filename and filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


# 定义一个处理CORS的中间件
@app.after_request
def add_cors_headers(response):
    response.headers['Access-Control-Allow-Origin'] = '*'
    response.headers['Access-Control-Allow-Headers'] = 'Content-Type'
    response.headers['Access-Control-Allow-Methods'] = 'GET, POST, PUT, DELETE, OPTIONS'
    return response


# 文件上传接口
@app.route(routerPrefix + '/upload', methods=['POST'])
def upload_file():
    # 检查是否有文件被上传
    if 'file' not in request.files:
        return jsonify({'error': '没有文件被上传'})

    file = request.files['file']
    # 获取额外的字段（identificationCode）
    identificationCode = int(request.form['identificationCode'])
    # 如果用户未选择文件，浏览器会发送一个空文件
    if file.filename == '':
        return jsonify({'error': '未选择文件'})

    # 检查文件类型是否允许
    if not allowed_file(file.filename):
        return jsonify({'error': '不允许的文件类型'})

    # 通过tcp下发到对应的连接上
    if identificationCode in clientsMap.keys():
        item = clientsMap[identificationCode]
        # 打开要发送的文件并发送文件数据到服务器
        data = file.read(1024000)
        fileName = "{}{}".format(int(time.time()), file.filename)
        # received_file_name = os.path.join("FileStorage", fileName)
        # with open(received_file_name, "wb") as localFile:
        #     localFile.write(data)
        while data:
            data = b'\x02\x01' + commonTools.Tools.strToBytes(fileName, 32) + data
            item.send(data)
            data = file.read(1024000)
        print(f"文件 {fileName} 已成功发送")
    else:
        return jsonify({'message': '未知的识别码： ' + str(identificationCode)})

    return jsonify(commonTools.Tools.okMsg("文件上传成功"))


# 获取当前所有tcp连接
@app.route(routerPrefix + '/conn/page', methods=['GET'])
def getAllConn():
    key_list = []
    for key in clientsMap:
        temp = {"code": key, "uptime": "2021-10-01 12:12:12"}
        key_list.append(temp)
    data = {
        "total": len(clientsMap),
        "records": key_list,
    }
    return jsonify(commonTools.Tools.okData(data))


# 登录接口
@app.route(routerPrefix + '/login', methods=['POST'])
def login():
    # 使用request.json来获取JSON格式的请求体数据
    token = commonTools.Tools.generateToken(request.json)
    return jsonify(commonTools.Tools.okData({"token": token, "realName": "管理员"}))


#
def httpServer():
    # 配置文件上传目录（将上传的文件保存在服务器的哪个目录下）
    app.run(host='0.0.0.0', port=httpPort)


if __name__ == '__main__':
    # 创建线程
    thread = threading.Thread(target=httpServer)

    # 启动http线程服务
    thread.start()

    # 启动tcp服务
    tcpServer()
